#pragma once

#include<iostream>
#include"Sem.hpp"
#include"Mutex.hpp"
#include<vector>

namespace RingQueueModule
{
    using namespace SemModule;
    using namespace MutexModule;

    template<typename T>
    class RingQueue
    {
    public:
        RingQueue(int cap)
        :_q(cap)
        ,_p_sem(cap)
        ,_c_sem(0)
        ,_c_pos(0)
        ,_p_pos(0)
        ,_cap(cap)
        {}
        ~RingQueue()
        {}

        void Equeue(T& in)
        {
            _p_sem.P();

            {
                MutexGuard _plock(_p_mutex);
                _q[_p_pos] = in;
                _p_pos = (_p_pos + 1) % _cap;
            }

            _c_sem.V();
        }

        void Pop(T* out)
        {
            _c_sem.P();

            {
                MutexGuard _clock(_c_mutex);
                *out = _q[_c_pos];
                _c_pos = (_c_pos + 1) % _cap;
            }

            _p_sem.V();
        }
    
    private:
        std::vector<T> _q;
        Sem _p_sem;
        Sem _c_sem;

        Mutex _p_mutex;
        Mutex _c_mutex;

        int _c_pos;
        int _p_pos;
        int _cap;
    };
}